package com.example.util.log;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

@Aspect
@Component
@Order(1)
@Slf4j
public class LogAspect {
    @Autowired
    private ObjectMapper mapper;

    //开始时间
    private Long visitTime;
    //访问的类
    private Class clazz;

    //定义切点表达式,指定通知功能被应用的范围
    @Pointcut("execution(public * com.example.controller.*.*(..))")
    public void aspect() {
    }

    @Before("aspect()")
    public void before(JoinPoint joinPoint) throws NoSuchMethodException{
        visitTime=System.currentTimeMillis();
        Date date =new Date(visitTime);
        clazz=joinPoint.getTarget().getClass();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        //访问的方法
        Method method;
        if (args == null || args.length==0){
            method =clazz.getMethod(methodName);
        }else {
            Class[] argsClasses = new Class[args.length];
            for (int i = 0; i < args.length; i++) {
                argsClasses[i] = args[i].getClass();
            }
            method =clazz.getMethod(methodName,argsClasses);
        }
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request=requestAttributes.getRequest();
        log.info("====================请求内容~开始====================");
        String requestMethod = request.getMethod();
        log.info("请求时间:"+new SimpleDateFormat().format(date));
        log.info("请求IP:"+request.getRemoteAddr());
        log.info("请求地址:"+request.getRequestURI());
        log.info("请求方式:"+requestMethod);
        log.info("请求类方法:"+joinPoint.getSignature());
        log.info("请求类方法参数:"+ Arrays.toString(joinPoint.getArgs()));
        if (clazz != null && method != null) {
            // 获取类上的 RequestMapping 注解
            RequestMapping clazzAnnotation = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
            if (clazzAnnotation != null) {
                String[] classValue = clazzAnnotation.value();
//                 获取方法上的 RequestMapping 注解
                if ("GET".equals(requestMethod)) {
                    GetMapping methodAnnotation = method.getAnnotation(GetMapping.class);
                    if (methodAnnotation != null) {
                        String[] methodValue = methodAnnotation.value();
                        if (classValue != null && classValue.length > 0 && methodValue != null && methodValue.length > 0) {
                            url(classValue, true, methodValue);
                        } else {
                            url(classValue, false, null);
                        }
                    } else {
                        url(classValue, false, null);
                    }
                } else {
                    PostMapping methodAnnotation = method.getAnnotation(PostMapping.class);
                    if (methodAnnotation != null) {
                        String[] methodValue = methodAnnotation.value();
                        if (classValue != null && classValue.length > 0 && methodValue != null && methodValue.length > 0) {
                            url(classValue, true, methodValue);
                        } else {
                            url(classValue, false, null);
                        }
                    } else {
                        url(classValue, false, null);
                    }
                }
            }
            log.info("类名{},方法名{}", clazz.getName(), methodName);
        }
        log.info("====================请求内容~结束====================");
    }

    /**
     * 在方法执行完成后打印返回内容
     * @param obj 返回值
     */
    @AfterReturning(returning = "obj",pointcut = "aspect()")
    public void methodAfterReturning(Object obj){
        long time =System.currentTimeMillis()-visitTime;
        log.info("执行时长:{}s",time);
        log.info("====================返回内容~开始====================");
        try{
            log.info(mapper.writeValueAsString(obj));
        } catch (JsonProcessingException e){
            e.printStackTrace();
            log.error("发生错误",e);
        }
        log.info("====================返回内容~结束====================");
    }
    private void url(String[] classValue, boolean b, String[] value) {
        String url;
        if (b){
            url = classValue[0]+value[0];
            log.info("url:{}", url);
        }
    }
}












